#include "Types.h"
#include "loopqueue.h"

#pragma pack(1)
typedef struct _LOOP_DATA_s_
{
    UINT16 usLen;
    UINT8 aucData[0];
}LOOP_DATA_s;
#pragma pack()
 
/**********************************************************
 * Function Name:        LoopQueue_Create
 * Description:          alloc memory for queue
 * Parameters[in]:       IN INT32 iQSize
                         IN INT32 iESize
                         INOUT LOOP_QUEUE_s **ppstQ
 * Parameters[out]:      INOUT LOOP_QUEUE_s **ppstQ
 * ReturnValue:          ULONG
 * Author:               liuke
 * Date:                 2020.05.26
***********************************************************/
ULONG LoopQueue_Create(IN INT32 iQSize, IN INT32 iESize, INOUT LOOP_QUEUE_s **ppstQ)
{
    INT32 i = 0;

    *ppstQ = (LOOP_QUEUE_s *)calloc(sizeof(LOOP_QUEUE_s), 1);
    if (*ppstQ == NULL)
    {
        return STAT_ERR_CALLOC;
    }

    (*ppstQ)->front = 0;         
    (*ppstQ)->rear = 0;
    (*ppstQ)->maxsize = iQSize;
    (*ppstQ)->elesize = iESize + sizeof(LOOP_DATA_s);

    (*ppstQ)->ppBase = (UINT8 **)calloc(sizeof(UINT8 *), iQSize);
    if ((*ppstQ)->ppBase == NULL)
    {
        free(*ppstQ);
        *ppstQ = NULL;
        return STAT_ERR_CALLOC;
    }

    for(i = 0; i < iQSize; i++)
    {
        (*ppstQ)->ppBase[i] = (UINT8 *)calloc(sizeof(UINT8), (*ppstQ)->elesize);
        if ((*ppstQ)->ppBase[i] == NULL)
	{
            goto ERR_RETURN;
        }
    }
	
    return STAT_SUCCEED;

ERR_RETURN:
    for(i = 0; i < iQSize; i++)
    {
        if ((*ppstQ)->ppBase[i] != NULL)
        {
            free((*ppstQ)->ppBase[i]);
            (*ppstQ)->ppBase[i] = NULL;
        }
    }

    free((*ppstQ)->ppBase);
    (*ppstQ)->ppBase = NULL;

    free(*ppstQ);
    *ppstQ = NULL;

    return STAT_ERR_CALLOC;
}

/**********************************************************
 * Function Name:        LoopQueue_isFull
 * Description:          check if queue full
 * Parameters[in]:       IN LOOP_QUEUE_s *Q
 * Parameters[out]:      void
 * ReturnValue:          BOOL
 * Author:               liuke
 * Date:                 2020.05.26
***********************************************************/
BOOL LoopQueue_isFull(IN LOOP_QUEUE_s *Q)
{
    if(Q->front == ((Q->rear + 1) % Q->maxsize))
        return BOOL_TRUE;
    else
        return BOOL_FALSE;
}

/**********************************************************
 * Function Name:        LoopQueue_isEmpty
 * Description:          check if queue empty
 * Parameters[in]:       IN LOOP_QUEUE_s * Q
 * Parameters[out]:      void
 * ReturnValue:          BOOL
 * Author:               liuke
 * Date:                 2020.05.26
***********************************************************/
BOOL LoopQueue_isEmpty(IN LOOP_QUEUE_s * Q)
{
    if(Q->front == Q->rear)
        return BOOL_TRUE;
    else
        return BOOL_FALSE;
}

/**********************************************************
 * Function Name:        LoopQueue_Enqueue
 * Description:          pop element from queue
 * Parameters[in]:       IN LOOP_QUEUE_s * Q
                         IN UINT8 *val
                         IN UINT16 uslen
 * Parameters[out]:      void
 * ReturnValue:          ULONG
 * Author:               liuke
 * Date:                 2020.05.26
***********************************************************/
ULONG LoopQueue_Enqueue(IN LOOP_QUEUE_s * Q, IN UINT8 *val, IN UINT16 usLen)
{
    LOOP_DATA_s *pstData = NULL;
    
    if ((Q == NULL) || (val == NULL) || ((usLen + sizeof(LOOP_DATA_s)) > Q->elesize))
    {
        return  STAT_ERR_INVAILD_PARAM;   
    }
    
    if(LoopQueue_isFull(Q))
    {
        return STAT_ERR_QUEUE_FULL;
    }
	
    pstData = (LOOP_DATA_s *)(Q->ppBase[Q->rear]);
    pstData->usLen = usLen;
    memcpy(pstData->aucData, val, usLen);
    pstData->aucData[usLen] = 0;
    Q->rear = (Q->rear + 1) % Q->maxsize;
    
    return STAT_SUCCEED;
}

/**********************************************************
 * Function Name:        LoopQueue_Dequeue
 * Description:          push into queue
 * Parameters[in]:       IN LOOP_QUEUE_s * Q
                         INOUT UINT8 *val
 * Parameters[out]:      INOUT UINT8 *val
                         OUT UINT16 *pusLen
 * ReturnValue:          ULONG
 * Author:               liuke
 * Date:                 2020.05.26
***********************************************************/
ULONG LoopQueue_Dequeue(IN LOOP_QUEUE_s * Q, INOUT UINT8 *val, OUT UINT16 *pusLen)
{
    LOOP_DATA_s *pstData = NULL;
    
    if ((Q == NULL) || (pusLen == NULL))
    {
        return  STAT_ERR_INVAILD_PARAM;   
    }

    if(LoopQueue_isEmpty(Q))
    {
        return STAT_ERR_QUEUE_EMPTY;
    }

    pstData = (LOOP_DATA_s *)(Q->ppBase[Q->front]);
    *pusLen = pstData->usLen;
	memcpy(val, pstData->aucData, *pusLen);
	Q->front = (Q->front + 1) % Q->maxsize;
	
	return STAT_SUCCEED;
}

/**********************************************************
 * Function Name:        LoopQueue_GetNext
 * Description:          读取队列第一个数据,不移动指针
 * Parameters[in]:       IN LOOP_QUEUE_s * Q
                         INOUT UINT8 *val
 * Parameters[out]:      INOUT UINT8 *val
                         OUT UINT16 *pusLen
 * ReturnValue:          ULONG
 * Author:               liuke
 * Date:                 2020.05.26
***********************************************************/
ULONG LoopQueue_GetHead(IN LOOP_QUEUE_s * Q, INOUT UINT8 *val, OUT UINT16 *pusLen)
{
    LOOP_DATA_s *pstData = NULL;
    
    if ((Q == NULL) || (pusLen == NULL))
    {
        return  STAT_ERR_INVAILD_PARAM;   
    }

    if(LoopQueue_isEmpty(Q))
    {
        return STAT_ERR_QUEUE_EMPTY;
    }
    
    pstData = (LOOP_DATA_s *)(Q->ppBase[Q->front]);
    *pusLen = pstData->usLen;
	memcpy(val, pstData->aucData, *pusLen);
	
	return STAT_SUCCEED;
}

/**********************************************************
 * Function Name:        LoopQueue_GetNext
 * Description:          读取队列下一个队首
 * Parameters[in]:       IN LOOP_QUEUE_s * Q
                         INOUT UINT8 *val
 * Parameters[out]:      INOUT UINT8 *val
                         OUT UINT16 *pusLen
 * ReturnValue:          ULONG
 * Author:               liuke
 * Date:                 2020.05.26
***********************************************************/
ULONG LoopQueue_GetNext(IN LOOP_QUEUE_s * Q, INOUT UINT8 *val, OUT UINT16 *pusLen)
{
    LOOP_DATA_s *pstData = NULL;
    
    if ((Q == NULL) || (pusLen == NULL))
    {
        return  STAT_ERR_INVAILD_PARAM;   
    }

    if(LoopQueue_isEmpty(Q))
    {
        return STAT_ERR_QUEUE_EMPTY;
    }

    Q->front = (Q->front + 1) % Q->maxsize;
    pstData = (LOOP_DATA_s *)(Q->ppBase[Q->front]);
    *pusLen = pstData->usLen;
    memcpy(val, pstData->aucData, *pusLen);
	
    return STAT_SUCCEED;
}

/**********************************************************
 * Function Name:        LoopQueue_destory
 * Description:          delete queue
 * Parameters[in]:       INOUT LOOP_QUEUE_s **ppstQ
 * Parameters[out]:      INOUT LOOP_QUEUE_s **ppstQ
 * ReturnValue:          void
 * Author:               liuke
 * Date:                 2020.05.26
***********************************************************/
void LoopQueue_destory(INOUT LOOP_QUEUE_s **ppstQ)
{
    UINT16 i = 0;

    for (i = 0; i < (*ppstQ)->maxsize; i++)
    {
        if ((*ppstQ)->ppBase[i] != NULL)
        {
            free((*ppstQ)->ppBase[i]);
            (*ppstQ)->ppBase[i] = NULL;
        }
    }

    free((*ppstQ)->ppBase);
    (*ppstQ)->ppBase = NULL;

    free(*ppstQ);
    *ppstQ = NULL;

    return;
}

